package com.jlpay.open.jlpay.sdk.java.sign;

import com.jlpay.open.jlpay.sdk.java.http.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

/**
 * @author zhaomeixia
 * @since 2024/2/20
 */
public class SignVerifierManager {

    private static final Logger LOGGER = LoggerFactory.getLogger(SignVerifierManager.class);

    private final SignVerifier signVerifier;

    public SignVerifierManager(final SignVerifier signVerifier) {
        this.signVerifier = signVerifier;
    }

    public String sign(HttpRequest request) {
        SignData signData = SignData.builder()
                .method(request.getMethod().name())
                .uri(buildUri(request.getUrl()))
                .timestamp(request.getHeaders().get(JlpayHttpHeaders.V5.TIMESTAMP))
                .nonce(request.getHeaders().get(JlpayHttpHeaders.V5.NONCE))
                .body(request.getBody() != null ? request.getBody() : "")
                .build();
        String signContent = signData.buildSignContent();
        LOGGER.debug("sign content: {}", signContent);
        String sign = signVerifier.sign(signContent, request.getHeaders().get(JlpayHttpHeaders.V5.SIGN_ALG));
        LOGGER.debug("signature: {}", sign);
        return sign;
    }


    public boolean verify(HttpRequest request, HttpResponse response) {
        String sign = response.getHeaders().get(JlpayHttpHeaders.V5.SIGN);
        if (sign == null) {
            LOGGER.warn("signature is null");
            return false;
        }
        LOGGER.debug("verify signature: {}", sign);
        SignData signData = SignData.builder()
                .method(request.getMethod().name())
                .uri(buildUri(request.getUrl()))
                .timestamp(response.getHeaders().get(JlpayHttpHeaders.V5.TIMESTAMP))
                .nonce(response.getHeaders().get(JlpayHttpHeaders.V5.NONCE))
                .body(response.getBody())
                .build();

        String signContent = signData.buildSignContent();
        LOGGER.debug("verify content: {}", signContent);
        return signVerifier.verify(signContent, sign, response.getHeaders().get(JlpayHttpHeaders.V5.SIGN_ALG));
    }

    public String sign(MultipartHttpRequest request) {
        SignData signData = SignData.builder()
                .method(request.getMethod().name())
                .uri(buildUri(request.getUrl()))
                .timestamp(request.getHeaders().get(JlpayHttpHeaders.V5.TIMESTAMP))
                .nonce(request.getHeaders().get(JlpayHttpHeaders.V5.NONCE))
                .body(request.getMeta().toString())
                .build();
        String signContent = signData.buildSignContent();
        LOGGER.debug("sign content: {}", signContent);
        String sign = signVerifier.sign(signContent, request.getHeaders().get(JlpayHttpHeaders.V5.SIGN_ALG));
        LOGGER.debug("signature: {}", sign);
        return sign;
    }

    public boolean verify(MultipartHttpRequest request, HttpResponse response) {
        String sign = response.getHeaders().get(JlpayHttpHeaders.V5.SIGN);
        if (sign == null) {
            LOGGER.warn("signature is null");
            return false;
        }
        LOGGER.debug("verify signature: {}", sign);
        SignData signData = SignData.builder()
                .method(HttpMethod.POST.name())
                .uri(buildUri(request.getUrl()))
                .timestamp(response.getHeaders().get(JlpayHttpHeaders.V5.TIMESTAMP))
                .nonce(response.getHeaders().get(JlpayHttpHeaders.V5.NONCE))
                .body(response.getBody())
                .build();

        String signContent = signData.buildSignContent();
        LOGGER.debug("verify content: {}", signContent);
        return signVerifier.verify(signContent, sign, response.getHeaders().get(JlpayHttpHeaders.V5.SIGN_ALG));
    }

    private String buildUri(URL url) {
        URI uri;
        try {
            uri = url.toURI();
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException("Invalid uri syntax", e);
        }
        String result = uri.getRawPath();
        if (uri.getQuery() != null) {
            result += "?" + uri.getRawQuery();
        }
        return result;
    }
}
